<?php

namespace app\console\controller;

use mon\env\Config;
use mon\util\Instance;
use app\model\ChatAppModel;
use app\model\ChatWaiterModel;
use GatewayWorker\Lib\Gateway;
use app\model\ChatMessageModel;
use app\model\ChatVisitorModel;
use app\model\ChatMessageRelationModel;

/**
 * 游客链接服务
 */
class VisitorController
{
    use Instance;

    /**
     * 需要验证登录的指令
     *
     * @var array
     */
    protected $loginType = ['send', 'close'];

    /**
     * 执行指令回调业务
     *
     * @param array $query 请求参数
     * @return void
     */
    public function handle($query, $client_id)
    {
        if (!isset($query['type'])) {
            return Gateway::sendToCurrentClient($this->result(420, 'cmd unrecognized'));
        }
        // 判断需要登录的请求
        if (in_array($query['type'], $this->loginType) && !isset($_SESSION['uid'])) {
            return Gateway::sendToCurrentClient($this->result(403, 'cmd unrecognized login'));
        }
        switch ($query['type']) {
            case 'ping':
                // 客户端心跳
                Gateway::sendToCurrentClient($this->result(200, 'pong'));
                break;
            case 'login':
                // 客户端创建通信
                $this->login($query, $client_id);
                break;
            case 'send':
                $this->send($query);
                break;
            case 'close':
                $this->close($query);
                break;
        }
    }

    /**
     * 结束对话
     *
     * @param array $data
     * @return void
     */
    protected function close($data)
    {
        $result = [];
        $result['type'] = 'visitorExit';
        // 访客的标识uid
        $result['client'] = $_SESSION['uid'];
        Gateway::sendToUid($data['to'], $this->result(200, 'success', $result));
        unset($result);
    }


    /**
     * 发送信息
     *
     * @param array $data
     * @return void
     */
    protected function send($data)
    {
        if (!isset($_SESSION['app']) || empty($_SESSION['app'])) {
            return Gateway::sendToCurrentClient($this->result(404, 'params faild'));
        }
        $nowTime = time();
        $_SESSION['last_send_time'] = $nowTime;
        $result = [];
        $result['type'] = $data['dataType'];
        $result['content'] = $data['content'];
        $result['from'] = $_SESSION['uid'];
        $result["time"] = $nowTime;
        // 发给访客
        Gateway::sendToCurrentClient($this->result(200, 'success', $result));
        // 发给客服
        $result['visitid'] = $_SESSION['uid'];
        Gateway::sendToUid($data['to'], $this->result(200, 'success', $result));
        unset($result);
        // 会话内容入库
        if (!isset($data['to']) || is_null($data['to'])) {
            // 未存在接待的客户ID，默认为留言
            $data['to'] = 0;
        }

        // Gateway::sendToCurrentClient($this->result(200, 'ok', [
        //     'type'      => 'card',
        //     'visitid'   => $data['to'],
        //     'from'      => $_SESSION['uid'],
        //     'img'       => 'https://z3.ax1x.com/2020/11/20/DQ1Tns.jpg',
        //     'title'     => '测试图文内容',
        //     'desc'      => '测试图文内容描述',
        //     'link'      =>  'http://baidu.com',
        //     'time'      => $nowTime
        // ]));

        // 会话信息入库
        $chat_relation = ChatMessageRelationModel::instance()->record($_SESSION['app'], code2id($data['to']), $_SESSION['uid']);
        if ($chat_relation) {
            // 更新最后通信时间
            ChatMessageRelationModel::instance()->save(['near_time' => $nowTime], ['id' => $chat_relation]);
            $chat_content = json_encode(['type' => $data['dataType'], 'content' => $data['content'], 'from' => $_SESSION['uid'], 'to' => $data['to']], JSON_UNESCAPED_UNICODE);
            ChatMessageModel::instance()->record($chat_relation, $chat_content);
        }
    }

    /**
     * 游客登陆操作
     *
     * @see {"type":"login", "uid":"访客标识", "app":"所属系统"}
     * @param array $data
     * @return void
     */
    protected function login($data, $client_id)
    {
        // 验证参数
        if (!isset($data['app']) || empty($data['app'])) {
            return Gateway::sendToCurrentClient($this->result(404, 'params faild'));
        }
        // 验证是否有效的APP
        $appInfo = ChatAppModel::instance()->getInfo(['name' => $data['app'], 'status' => '1']);
        if (!$appInfo) {
            return Gateway::sendToCurrentClient($this->result(200, 'success', [
                'type'  => 'tips',
                'msg'   => '抱歉，应用客服服务未启用'
            ]));
        }
        // 获取应用配置
        $maxReception = $appInfo['receptnum'];
        // 生成用户ID
        $uid = empty($data['uid']) ? md5($client_id . microtime(true)) : $data['uid'];
        // 记录访客ID的uid及IP到数据库中
        $data_id = ChatVisitorModel::instance()->record($uid, $_SERVER['REMOTE_ADDR']);
        if (!$data_id) {
            return Gateway::sendToCurrentClient($this->result(501, 'success', [
                'type'  => 'tips',
                'msg'   => '抱歉，访客登记异常，请稍后再试'
            ]));
        }
        // 记录数据库中对应的ID
        $_SESSION['id'] = $data_id;
        // 个人标识
        $_SESSION['uid'] = $uid;
        // 所属关系app
        $_SESSION['app'] = $data['app'];
        // APP信息
        $_SESSION['app_title'] = $appInfo['title'];
        // 访客的ip信息
        $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
        // 角色类型
        $_SESSION['role'] = 'visitor';
        // 排队状态
        $_SESSION['state'] = "wait";
        // 访客或客服所属群组
        $_SESSION['group'] = "";
        // 用户默认头像
        $_SESSION['avatar'] = Config::instance()->get('chat.default_avatar');
        // uid绑定
        Gateway::bindUid($client_id, $uid);
        // 当前客服系统排队状态组
        Gateway::joinGroup($client_id, "wait_" . $data['app']);
        // 访客刷新页面的情况处理，查看链接的客服是否还在线，并且客服量是否超过10个。注意要判断是重新加载页面还是又另外打开一个页面
        // 当前客服是否可再分配标识
        $kefNoUse = false;
        // 是否指定客服人员
        if (isset($data['group']) && !empty($data['group'])) {
            // 获取客服链接ID
            $kfClientList = Gateway::getClientIdByUid($data['group']);
            // 客服是否在线
            if (!empty($kfClientList) && Gateway::isOnline($kfClientList[0])) {
                // 指定的客服在线，获取指定客服接待数
                $receptionCount = Gateway::getClientIdCountByGroup($data['group']);
                if ($receptionCount < $maxReception) {
                    $kefNoUse = true;
                }
            }
        }

        // 如果当前客服可分配
        if ($kefNoUse) {
            $_SESSION['state'] = 'chat';
            // 指定客服
            $_SESSION['group'] = $data['group'];
            Gateway::joinGroup($client_id, $data['group']);
            // 会话状态转移
            Gateway::leaveGroup($client_id, "wait_" . $data['app']);
            Gateway::joinGroup($client_id, "chat_" . $data['app']);

            // 发信息给访客
            $result = [];
            // 有客服接待事件
            $result['type'] = 'chat';
            $result['uid'] = $_SESSION['uid'];
            $result['group'] = $data['group'];
            $userInfo = ChatWaiterModel::instance()->getInfo(['id' => code2id($data['group'])]);
            if ($userInfo) {
                $nickname = '【' . $userInfo['nickname'] . '】';
            } else {
                $nickname = '';
            }
            $result['msg'] = '客服' . $nickname . '为您服务';
            Gateway::sendToCurrentClient($this->result(200, 'success', $result));
            unset($result);

            // 发信息给当前客服
            $result = [];
            $result['id'] = $_SESSION['id'];
            // 访客的信息, 用于更新访客列表
            $result['type'] = 'visitor';
            // 访客的ip信息
            $result['ip'] = $_SERVER['REMOTE_ADDR'];
            // 访客终端app
            $result['app'] = $data['app'];
            $result['app_title'] = $_SESSION['app_title'];
            // 访客的标识uid
            $result['client_uid'] = $_SESSION['uid'];
            $result['avatar'] = $_SESSION['avatar'];
            $result['time'] = time();
            Gateway::sendToUid($data['group'], $this->result(200, 'success', $result));
            unset($result);
        } else {
            // 获取当前客服系统客服在线数量
            $kefuNum = Gateway::getClientIdCountByGroup("kf_" . $data['app']);
            if ($kefuNum > 0) {
                // 获取当前客服应用的客服信息, 平均分配访客给客服
                $kefuList = Gateway::getClientSessionsByGroup("kf_" . $data['app']);
                // '客服id'=>'接待量'
                $kefu_uid_num = [];
                foreach ($kefuList as $kf_client_id => $kf_session) {
                    // 获取客服对应uid及相应的接待量
                    $kefu_uid_num[$kf_session['uid']] = Gateway::getClientIdCountByGroup($kf_session['uid']);
                }
                asort($kefu_uid_num);
                reset($kefu_uid_num);
                // 获取接待量最小的客服uid
                $kefu_uid = key($kefu_uid_num);
                // 获取接待量最小的客服的接待数量
                $kefu_reception_num = $kefu_uid_num[$kefu_uid];
                // 接待数小于客服最大接待数，链接客服
                if ($kefu_reception_num < $maxReception) {
                    // 指定客服
                    $_SESSION['group'] = $kefu_uid;
                    Gateway::joinGroup($client_id, $kefu_uid);
                    // 访客会话状态转移
                    Gateway::leaveGroup($client_id, "wait_" . $data['app']);
                    Gateway::joinGroup($client_id, "chat_" . $data['app']);
                    // 修改访客状态
                    $_SESSION['state'] = 'chat';
                    $result = [];
                    // 有客服接待事件
                    $result['type'] = 'chat';
                    $result['uid'] = $_SESSION['uid'];
                    $result['group'] = $kefu_uid;
                    $userInfo = ChatWaiterModel::instance()->getInfo(['id' => code2id($result['group'])]);
                    if ($userInfo) {
                        $nickname = '【' . $userInfo['nickname'] . '】';
                    } else {
                        $nickname = '';
                    }
                    // 客服昵称
                    $result['msg'] = "客服 " . $nickname . " 为您服务";
                    Gateway::sendToCurrentClient($this->result(200, 'success', $result));
                    unset($result);
                    // 发信息给当前客服
                    $result = [];
                    $result['id'] = $_SESSION['id'];
                    // 访客的信息, 用于更新访客列表
                    $result['type'] = 'visitor';
                    // 访客的ip信息
                    $result['ip'] = $_SERVER['REMOTE_ADDR'];
                    // 访客终端app
                    $result['app'] = $data['app'];
                    $result['app_title'] = $_SESSION['app_title'];
                    // 访客的标识uid
                    $result['client_uid'] = $_SESSION['uid'];
                    $result['avatar'] = $_SESSION['avatar'];
                    $result['time'] = time();
                    Gateway::sendToUid($kefu_uid, $this->result(200, 'success', $result));
                    unset($result);
                    // 会话关系入库
                    $chat_relation = ChatMessageRelationModel::instance()->record($_SESSION['app'], code2id($kefu_uid), $_SESSION['uid']);
                    if ($chat_relation) {
                        // 更新最后通信时间
                        ChatMessageRelationModel::instance()->save(['near_time' => time()], ['id' => $chat_relation]);
                    }
                } else {
                    // 超出规定接待量时，不允许再接待，当前访客处于排队中
                    $result = [];
                    // 没有分配客服，排队中
                    $result['type'] = 'wait';
                    $result['uid'] = $_SESSION['uid'];
                    $result['msg'] = '当前客服忙碌，请稍后咨询';
                    Gateway::sendToCurrentClient($this->result(200, 'success', $result));
                    unset($result);
                }
                unset($kefu_uid_num);
            } else {
                //没有客服在线
                $result = [];
                // 没有分配客服，排队中
                $result['type'] = 'wait';
                $result['uid'] = $_SESSION['uid'];
                $result['msg'] = '暂无在线客服接待，请稍候咨询';
                Gateway::sendToCurrentClient($this->result(200, 'success', $result));
                unset($result);
            }
        }
    }

    /**
     * 返回结果集
     *
     * @param integer $code
     * @param string $message
     * @param array $data
     * @param boolean $toJson
     * @return string
     */
    public function result($code, $message, $data = [], $toJson = true)
    {
        $data = [
            'code'  => $code,
            'msg'   => $message,
            'data'  => $data
        ];
        return $toJson ? json_encode($data, JSON_UNESCAPED_UNICODE) : $data;
    }
}
